﻿using RockBus.Configuration;
using RockBus.Configuration.Interfaces;
using RockBus.DataContracts;
using RockBus.Logging.Interfaces;
using RockBus.Routing.Interfaces;
using RockBus.ConfigurationRepository.Interfaces;
using RockBus.Threading;
using System;
using System.Threading;

namespace RockBus.Routing
{
    public class ReadOnlyConfiguration : IReadOnlyConfiguration, IWithTimerCallback
    {
        public ReadOnlyConfiguration(
            ILogger logger,
            IConfigurationManager configurationManager)
        {
            this.Logger = logger;
            this.ConfigurationManager = configurationManager;

            // Initialize with defaults, which will be overridden whenever the OnChanged event fires
            this.InternalConfiguration = InternalConfiguration.CreateDefaultInternalConfiguration();
            this.SubscriberConfiguration = new SubscriberConfiguration();
            this.PublisherConfiguration = new PublisherConfiguration();

            this.TimerIntervalMs = Timeout.Infinite;
            this.InitializationTimer = new Timer(((IWithTimerCallback)this).ExecuteTimerCallback, null, this.TimerIntervalMs, this.TimerIntervalMs);
        }

        private ILogger Logger { get; set; }

        private IConfigurationManager ConfigurationManager { get; set; }

        private int TimerIntervalMs { get; set; }

        private Timer InitializationTimer { get; set; }

        #region IReadOnlyConfiguration

        public InternalConfiguration InternalConfiguration { get; private set; }

        public SubscriberConfiguration SubscriberConfiguration { get; private set; }

        public PublisherConfiguration PublisherConfiguration { get; private set; }

        public event EventHandler<EventArgs> OnChanged;

        #endregion IReadOnlyConfiguration

        void IWithTimerCallback.ExecuteTimerCallback(object state)
        {
            this.InternalConfiguration = this.ConfigurationManager.GetInternalConfiguration(new GetInternalConfigurationRequest()).InternalConfiguration;
            this.SubscriberConfiguration = this.ConfigurationManager.GetSubscriberConfiguration();
            this.PublisherConfiguration = this.ConfigurationManager.GetPublisherConfiguration();

            if (this.TimerIntervalMs != this.InternalConfiguration.ReinitializationIntervalMs)
            {
                this.TimerIntervalMs = this.InternalConfiguration.ReinitializationIntervalMs;
                this.InitializationTimer.Change(this.TimerIntervalMs, this.TimerIntervalMs);
            }

            this.FireOnSubscriptionConfigurationChanged();
        }

        public void Refresh()
        {
            ((IWithTimerCallback)this).ExecuteTimerCallback(null);
        }

        private void FireOnSubscriptionConfigurationChanged()
        {
            this.OnChanged.Fire(this, new EventArgs());
        }
    }
}